/* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Mario Orsi
   This file is part of Brahms.
   Brahms is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
   Brahms is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
   You should have received a copy of the GNU General Public License along with Brahms.  If not, see <http://www.gnu.org/licenses/>. */

/* checkpts.c: equipment to save the system state through checkpoint/restart files. 
   Everything that the program is unable to reconstruct quickly from available information 
   must be included in the chekpoint file [Rapaport, pp.500-504]
   For added security, two copies of the checkpoint file will be maintained and they 
   will be updated alternately, thus if the job aborts while writing the file (e.g. due to
   lack of file space) the previous copy will still be available.  
   Functions *Checkpoint access the chkpt files. */

#include "dataStructs.h"

extern Site *site;
extern VecR *siteForce, *siteTorque, *siteCoords, *siteVelocity, *siteAngMom, *siteOrientVec;
extern RMat *siteRotMat; 
extern VecR region; 
extern real temperature, timeNow;
extern RMat boxMatrix;
extern Prop totEnergy, potEnergy, systemTemperature, pressure;
extern const int nSites, runId, doCheckpoint;
extern int newRun, stepCount;

void ErrExit (int code); // external function declaration

enum {FL_CHECKA, FL_CHECKB, FL_CKLAST, FL_SNAP};

/* xx is replaced by progId ("md") and the two-digit serial 
   number nn is replaced by runId (external variable from input file), 
   that identifies the run */
char *fileNameR[] = { "xxnnchecka.data", "xxnncheckb.data", "xxnncklast.data", "xxnnsnap.data" }, fileName[ 5 ][ 20 ];
char *progId = "md";

const char CHAR_ZERO = '0'; 

void PutCheckpoint() // [Rapaport, p.502]
{
  int fOk, fVal;
  FILE *fp;

  fOk = 0;
  if ((fp = fopen (fileName[FL_CKLAST], "r+")) != 0) { // "r+" means "read and write"
    fVal = FL_CHECKA + FL_CHECKB - (fgetc (fp) - CHAR_ZERO);
    rewind (fp);
    fputc (CHAR_ZERO + fVal, fp);
    fclose (fp);
    fOk = 1;
  }
  if (fOk && (fp = fopen (fileName[fVal], "w")) != 0) {
    WriteF( stepCount );
    WriteF( timeNow );
    WriteF( totEnergy );
    WriteF( potEnergy );
    WriteF( pressure );
    WriteF( systemTemperature );
    WriteF( region );
    WriteF( boxMatrix );
    WriteFN( site, nSites );
    WriteFN( siteForce, nSites );
    WriteFN( siteTorque, nSites );
    WriteFN( siteCoords, nSites );
    WriteFN( siteVelocity, nSites );
    WriteFN( siteAngMom, nSites );
    WriteFN( siteOrientVec, nSites );
    WriteFN( siteRotMat, nSites );
   
    if (ferror (fp)) fOk = 0;
    fclose (fp);
  } else fOk = 0;
  if (! fOk) ErrExit (ERR_CHECKPT_WRITE);
}

void GetCheckpoint() // [Rapaport, p.503]
{
  int fOk, fVal;
  FILE *fp;

  fOk = 0;
  if ( (fp = fopen( fileName[ FL_CKLAST ], "r" ) ) != 0 ) {
    fVal = fgetc( fp ) - CHAR_ZERO;
    fclose( fp );
    fOk = 1;
  }
  if ( fOk && ( fp = fopen( fileName[ fVal ], "r" ) ) != 0 ) {
    ReadF( stepCount );
    ReadF( timeNow );
    ReadF( totEnergy );
    ReadF( potEnergy );
    ReadF( pressure );
    ReadF( systemTemperature );
    ReadF( region );
    ReadF( boxMatrix );
    ReadFN( site, nSites );
    ReadFN( siteForce, nSites );
    ReadFN( siteTorque, nSites );
    ReadFN( siteCoords, nSites );
    ReadFN( siteVelocity, nSites );
    ReadFN( siteAngMom, nSites );
    ReadFN( siteOrientVec, nSites );
    ReadFN( siteRotMat, nSites );
    
    if ( ferror( fp ) ) fOk = 0;
    fclose( fp );
  } else fOk = 0;
  if ( !fOk ) ErrExit( ERR_CHECKPT_READ );
  printf( "Simulation region (from checkpoint): ( %5.3f x %5.3f x %5.3f ) nm\n", region.x, region.y, region.z ); 
}

void SetupCheckpointFiles( FILE *logFilePtr ) // [Rapaport, p.501]
{
  FILE *fp;
  int k;
 
  fprintf( logFilePtr, "SetupCheckpointFiles... "); fflush(logFilePtr);

  for ( k = 0; k < sizeof( fileNameR ) / sizeof( fileNameR[ 0 ] ); k++ ) {
    strcpy( fileName[ k ], fileNameR[ k ] );
    fileName[ k ][ 0 ] = progId[ 0 ];
    fileName[ k ][ 1 ] = progId[ 1 ];
    fileName[ k ][ 2 ] = runId / 10 + CHAR_ZERO;
    fileName[ k ][ 3 ] = runId % 10 + CHAR_ZERO;
  }
  if ( !doCheckpoint ) {   
    newRun = 1; 
  } else if ( ( fp = fopen( fileName[ FL_CKLAST ], "r" ) ) != 0 ) {
    newRun = 0;
    fclose( fp );
  } else {
    newRun = 1;
    fp = fopen( fileName[ FL_CHECKA ], "w" );
    fclose( fp );
    fp = fopen( fileName[ FL_CHECKB ], "w" );
    fclose( fp );
    fp = fopen( fileName[ FL_CKLAST ], "w" );
    fputc( CHAR_ZERO + FL_CHECKA, fp );
    fclose( fp );
  }
  fprintf( logFilePtr, "done\n"); fflush(logFilePtr);
}
